#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

#include "sem_priv.h"

// ------- Variáveis -------- //
dados_cmp cmp;
FILE *f;
typedef struct{ int id; int wait; }to_thread;

void *leitor2(void *arg){
    to_thread* struct_c = (to_thread*) arg;
    int id = struct_c->id;
    int i;
    sem_wait(&cmp.mut_print);
    printf("Gerente %d criado.\n", id);
    sem_post(&cmp.mut_print);

    sem_wait(&cmp.mutex);
    if(cmp.esc_wait > 0){
        cmp.lei_wait++;
        sem_post(&cmp.mutex);
        sem_wait(&cmp.lei_sleep);
    }
    else {
        cmp.lei_proc++;
        sem_post(&cmp.mutex);
    }

    sem_wait(&cmp.mut_print);
    printf("O gerente %d esta verificando o estoque:\t", id);
    for(i=0; i<ESTOQUE_MAX; i++) printf("[%c]", cmp.estoque[i]);
    printf("\n");
    sem_post(&cmp.mut_print);

    sem_wait(&cmp.mutex);
    cmp.lei_proc--;
    if(cmp.lei_proc == 0 && cmp.esc_wait > 0){
        cmp.esc_wait--;
        sem_post(&cmp.esc_sleep);
    }
    else {
        sem_post(&cmp.mutex);
    }
    sleep(struct_c->wait);
}

int main(int argc, char *argv[]){
    f = fopen("log.txt", "w");
    to_thread escdata;
    void *status;

    // Inicializa variáveis
    int i;
    cmp.estoque_index = 0;
    for(i=0; i<ESTOQUE_MAX; i++) cmp.estoque[i] = ' ';

    // inicializa semafaros
    sem_init(&cmp.mutex, 0, 1);
    sem_init(&cmp.lei_sleep, 0, 0);
    sem_init(&cmp.esc_sleep, 0, 0);
    sem_init(&cmp.mut_print, 0, 1);

    // threads
    pthread_t esc, leit;
    if(argc < 2){
        for(i=0; i<QT_PRODUTORES; i++){
            pthread_create(&esc, NULL, escritor, (void*)i);
        }
        for(i=0; i<QT_GERENTES; i++){
            pthread_create(&leit, NULL, leitor, (void*)i);
        }
        sleep(2);
        printf("saindo..\n");
        return 0;
    }
    else {
        escdata.id = 1;
        escdata.wait = 4;
        pthread_create(&leit, NULL, leitor2, (void*) &escdata);
        printf("Há baby!\n");
        pthread_join(leit, &status);

    }
}

void *leitor(void *arg){
    int id = (int) arg;
    int i;
    sem_wait(&cmp.mut_print);
    printf("Gerente %d criado.\n", id);
    sem_post(&cmp.mut_print);

    sem_wait(&cmp.mutex);
    if(cmp.esc_wait > 0){
        cmp.lei_wait++;
        sem_post(&cmp.mutex);
        sem_wait(&cmp.lei_sleep);
    }
    else {
        cmp.lei_proc++;
        sem_post(&cmp.mutex);
    }

    sem_wait(&cmp.mut_print);
    printf("O gerente %d esta verificando o estoque:\t", id);
    for(i=0; i<ESTOQUE_MAX; i++) printf("[%c]", cmp.estoque[i]);
    printf("\n");
    sem_post(&cmp.mut_print);

    sem_wait(&cmp.mutex);
    cmp.lei_proc--;
    if(cmp.lei_proc == 0 && cmp.esc_wait > 0){
        cmp.esc_wait--;
        sem_post(&cmp.esc_sleep);
    }
    else {
        sem_post(&cmp.mutex);
    }
}

void *escritor(void *arg){
    int id = (int) arg;

    sem_wait(&cmp.mut_print);
    printf("Produtor %d criado\n", id);
    sem_post(&cmp.mut_print);

    sem_wait(&cmp.mutex);
    if(cmp.lei_proc > 0){
        cmp.esc_wait++;
        sem_post(&cmp.mutex);
        sem_wait(&cmp.esc_sleep);
    }

    cmp.estoque[cmp.estoque_index++] = 'X';
    fprintf(f, "Produtor %d incrementou o estoque\n", id);

    if(cmp.lei_wait > 0){
        while(cmp.lei_wait > 0){
            cmp.lei_wait--;
            cmp.lei_proc++;
            sem_post(&cmp.lei_sleep);
        }
    }
    else {
        if(cmp.esc_wait > 0){
            cmp.esc_wait--;
            sem_post(&cmp.esc_sleep);
        }
        else {
            sem_post(&cmp.mutex);
        }
    }
}

